package com.netspider.downloader;

import java.util.Properties;
import java.util.Vector;
import java.util.logging.Level;

import com.netspider.utils.Log;
import com.netspider.utils.Prop;

public class DLScheduler
{
	private DLScheduler()
	{
		this.queue = new URLQueue();
		this.stop = true;
		this.doTaskCount = 0;
		this.maxTaskCount = -1;
		this.schedulerThread = new Thread(new Scheduler());
		this.downloaders = new Vector<Downloader>();
		this.maxDownloaderCount = 3;
		Log.getLogger().log(Level.FINE, "[DLScheduler]DLScheduler create");
	}

	/**
	 * Description: start the Download Scheduler
	 * 
	 */
	public void start()
	{
		this.stop = false;
		this.schedulerThread.start();
		Log.getLogger().log(Level.FINE, "[DLScheduler]scheduler Thread will start");
	}
	
	/**
	 * 
	 * Description: stop the Download Scheduler
	 * 
	 */
	public void stop()
	{
		Log.getLogger().log(Level.FINE, "[DLScheduler]scheduler Thread will stop");
		this.stop = true;
	}
	
	
	/**
	 * 
	 * Description: add a task to Download Scheduler
	 * @param url   the url of a web page
	 */
	public void addTask(URL url)
	{
		Log.getLogger().log(Level.FINE, "[DLScheduler]add a new task");
		queue.add(url);
	}
	
	/**
	 * 
	 * Description: remove a task from Download Scheduler task queue
	 * @param url   the url of a web page
	 */
	public void delTask(URL url)
	{
		Log.getLogger().log(Level.FINE, "[DLScheduler]remove a task");
		queue.remove(url);
	}
	
	public void setMaxTaskCount(int count)
	{
		Log.getLogger().log(Level.FINE, "[DLScheduler]set maxTaskCount to " + count);
		this.maxTaskCount = count;
	}
	
	public void setMaxDownloaderCount(int count)
	{
		Log.getLogger().log(Level.FINE, "[DLScheduler]set maxDownloaderCount to " + count);
		maxDownloaderCount = count;
	}
	
	private boolean isReachMaxTaskCount()
	{
		//if the maxTaskCount have been setted to -1 means we can not stop never
		if(maxTaskCount == -1)
		{
			return false;
		}
		
		return doTaskCount >= maxTaskCount; 
	}
	
	public void init()
	{
		Properties prop = Prop.getProp();
		maxTaskCount = Integer.parseInt(prop.getProperty(prop_maxTaskCount, "-1"));
		maxDownloaderCount = Integer.parseInt(prop.getProperty(prop_maxDownloaderCount, "3"));
		
		Log.getLogger().log(Level.FINE, "[DLScheduler]DLScheduler inited");
	}
	
	@Override
	protected void finalize() throws Throwable
	{
		this.stop = true;
		Log.getLogger().log(Level.FINE, "[DLScheduler]DLScheduler destory");
		super.finalize();
	}
	
	private Downloader getIdleDownloader()
	{
		for(int i=0; i< this.downloaders.size(); i++)
		{
			Downloader downloader = this.downloaders.get(i);
			if(downloader.isIdle())
			{
				Log.getLogger().log(Level.FINE, "[DLScheduler]find an idle downloader, its id is " + downloader.getID());
				return downloader;
			}
		}
		//if all the downloader in list is busy, test whether we can create more downloader
		if(this.downloaders.size() < this.maxDownloaderCount)
		{
			Downloader downloader = new Downloader(this.downloaders.size());
			Log.getLogger().log(Level.FINE, "[DLScheduler]create an new download for the task its id is " + downloader.getID());
			downloaders.add(downloader);
			return downloader;
		}
		//all the downloader in list is busy, and we are not allow to create more downloader, so we have to return null
		return null;
	}
	
	private void SchedulerTask(URL url)
	{
		Downloader downloader = getIdleDownloader();
		while(downloader == null)
		{
			try
			{
				Log.getLogger().log(Level.INFO, "[DLScheduler]no idle downloader retry after 100ms");
				Thread.sleep(100);
				downloader = getIdleDownloader();
			}
			catch (InterruptedException e)
			{
				Log.getLogger().log(Level.WARNING, "[DLScheduler]excetion happen when Scheduler Task", e);
			}
			
		}
		
		
		downloader.doTask(url);
		
		doTaskCount++;
		Log.getLogger().log(Level.INFO, "[DLScheduler]done task count is " + doTaskCount);
	}
	
	private class Scheduler implements Runnable
	{
		@Override
		public void run()
		{
			while(!DLScheduler.this.stop && !DLScheduler.this.isReachMaxTaskCount())
			{
				if(!queue.isEmpty())
				{
					URL url = queue.remove();
					SchedulerTask(url);
					try
					{
						Thread.sleep(1);
					}
					catch (InterruptedException e)
					{
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
				}
			}
		}

	}

	
	private Thread   schedulerThread = null;
	
	//the url queue which need to download
	private URLQueue queue;
	
	//if want to download force stop, set the flag to true
	private boolean  stop;
	
	//the max task count we want to download, if set as -1 means no limit;
	private int maxTaskCount;
	
	//the task count we have done;
	private int doTaskCount;
	
	private Vector<Downloader> downloaders;
	
	private int maxDownloaderCount;
	
	public static DLScheduler getInstance()
	{
		if(singleton == null)
		{
			singleton = new DLScheduler();
		}
		return singleton;
	}
	
	
	private static DLScheduler singleton = null;
	
	public static final String prop_maxTaskCount = "ro.DLScheduler.maxTaskCount";
	public static final String prop_maxDownloaderCount = "ro.DLScheduler.maxDownloaderCount";
	
	
	public static void test()
	{
		DLScheduler dlschedule = DLScheduler.getInstance(); 
		dlschedule.init();
		for(int i = 0; i<1000; i++)
		{
			dlschedule.addTask(new URL("1"));
		}
		dlschedule.start();
		while(true)
		{
			try
			{
				Thread.sleep(1000);
			}
			catch (InterruptedException e)
			{
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}

}
